﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Linq;
using BrainTechLLC;
using System.Windows.Threading;
using BrainTechLLC.WebCamLib3;
using System.Collections.Generic;
using System.Timers;
using BrainTechLLC.ImageOperators;
using BrainTechLLC.FilterExtensions;
using WpfImageReceiver;
using BrainTechLLC.ImageOperatorsNonAForgeDependent;
using System.Diagnostics;
using System.IO;
using WpfImageDuplicates;

namespace WebCam
{
    /// <summary>
    /// Interaction logic for WebCamWindow.xaml
    /// </summary>
    public partial class WebCam3Window : Window
    {
        public VideoFeedProvider _feedProvider;
        public IVideoFeed _videoFeed;
        CameraHandler _handler;
        LocalVideoDevice _device;
        MotionProcessingViewModel _motionViewModel;
        Timer _updateTimer = new Timer(1000);
        DateTime _lastPlayedSound = DateTime.MinValue;
        public bool _communicationsInitialized;

        public static readonly DependencyProperty CommunicationsProperty =
            DependencyProperty.Register("Communications", typeof(Communications), typeof(WebCam3Window), new PropertyMetadata(null, OnCommunicationsPropertyChanged));

        public Communications Communications
        {
            get { return (Communications)GetValue(CommunicationsProperty); }
            set { SetValue(CommunicationsProperty, value); }
        }

        private static void OnCommunicationsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            WebCam3Window source = d as WebCam3Window;
            Communications vNew = e.NewValue as Communications;
            Communications vOld = e.OldValue as Communications;
            source.UpdateCommunications(vNew, vOld);
        }

        private void UpdateCommunications(Communications viewModel, Communications viewModelOld)
        {
            if (viewModel == viewModelOld)
                return;

            if (viewModelOld != null)
            {
                viewModelOld.PropertyChanged -= Communications_PropertyChanged;
            }

            Communications = viewModel;
            Communications.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Communications_PropertyChanged);

            // Let the UI bind to the view-model.
            txtHostName.DataContext = Communications;
        }

        void Communications_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Connected" && Communications.Connected)
            {
                var feed = new GenericVideoFeed();
                webCamControl.cameraHandler = _handler;
                webCamControl.cameraHandler._videoFeed = feed;
                feed.StartCameraCapture();
                _feedProvider = new VideoFeedProvider(Communications, feed);
                _videoFeed = feed;
                webCamControl.BeginProcessing();
            }
        }

        private void btnMovementAlarm_Checked(object sender, RoutedEventArgs e)
        {
            this.Topmost = false;
            btnTopmost.IsChecked = false;
        }

        public WebCam3Window()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(WebCam3Window_Loaded);
            this.Closing += new System.ComponentModel.CancelEventHandler(WebCam3Window_Closing);

            _handler = new CameraHandler();
            _motionViewModel = new MotionProcessingViewModel(_handler, new MotionProcessing());
            _motionViewModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(_motionViewModel_PropertyChanged);
            _motionViewModel.RaiseMovementAlarm += new EventHandler(_motionViewModel_RaiseMovementAlarm);
            List<IPostProcessor> postProcessors = new List<IPostProcessor>();
            postProcessors.Add(_motionViewModel);
            webCamControl.SetPostProcessors(postProcessors);

            this.DataContext = _motionViewModel;
            mnuHostName.DataContext = Communications;

            _updateTimer.AutoReset = true;
            _updateTimer.Elapsed += new ElapsedEventHandler(_updateTimer_Elapsed);
            _updateTimer.Start();
        }


        void _motionViewModel_RaiseMovementAlarm(object sender, EventArgs e)
        {
            Dispatcher.BeginInvoke(new VoidDelegate(() =>
            {
                this.Topmost = true;
                btnTopmost.IsChecked = true;
                this.Activate();
                this.BringIntoView();
                this.Focus();

                if (_lastPlayedSound.AddSeconds(3) < DateTime.Now)
                {
                    _lastPlayedSound = DateTime.Now;
                    System.Media.SystemSounds.Exclamation.Play();

                    LaunchProgram();
                }
                btnMovementAlarm.IsChecked = false;
            }));
        }

        public void LaunchProgram()
        {
            try
            {
                string motionAlarmExe = "c:\\MotionAlarm.exe";
                if (File.Exists(motionAlarmExe))
                {
                    Process p = new Process()
                    {
                        StartInfo = new ProcessStartInfo(motionAlarmExe)
                        {
                            UseShellExecute = false,
                            CreateNoWindow = false,
                            WindowStyle = ProcessWindowStyle.Normal,
                        }

                    };
                    p.Start();
                }

                var processes = Process.GetProcesses();

                for (int n = 0; n < processes.Length; n++)
                {
                    var proc = processes[n];
                    if (proc.ProcessName.IndexOf("wmplayer", StringComparison.OrdinalIgnoreCase) >= 0)
                    {
                        proc.Kill();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        void _motionViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "LastMotionDetected")
            {
                txtWarning.Visibility = Visibility.Visible;
            }
        }

        void _updateTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (webCamControl.cameraHandler != null)
            {
                Dispatcher.BeginInvoke(new VoidDelegate(() => UpdateFPS()));

                //if (webCamControl.cameraHandler._cameraProcessing)
                //{
                //    if (webCamControl.cameraHandler.LastProcessedFrame != DateTime.MinValue &&
                //        webCamControl.cameraHandler.LastProcessedFrame.AddSeconds(60) < DateTime.Now)
                //    {
                //        Dispatcher.BeginInvoke(() => DisplayNoFramesRecentlyReceivedWarning());
                //    }
                //    else
                //    {
                //        Dispatcher.BeginInvoke(() => ClearRecentFramesWarning());
                //    }
                //}
            }
        }

        public void ShowProps1()
        {
            PropertyGridWindow propGrid = new PropertyGridWindow() { Owner = this };
            propGrid.Loaded += new RoutedEventHandler(propGrid_Loaded1);
            propGrid.Show();
            propGrid.Topmost = true;
        }

        void propGrid_Loaded1(object sender, RoutedEventArgs e)
        {
            PropertyGridWindow propGrid = sender as PropertyGridWindow;
            propGrid.Instance = this._motionViewModel;
        }

        public void ShowProps2()
        {
            PropertyGridWindow propGrid = new PropertyGridWindow() { Owner = this }; // was Window1.MainWindow 
            propGrid.Loaded += new RoutedEventHandler(propGrid_Loaded2);
            propGrid.Show();
            propGrid.Topmost = true;
        }

        void propGrid_Loaded2(object sender, RoutedEventArgs e)
        {
            PropertyGridWindow propGrid = sender as PropertyGridWindow;
            propGrid.Instance = webCamControl.cameraHandler;
        }

        public void ClearRecentFramesWarning()
        {
            txtWarning.Visibility = Visibility.Collapsed;
        }

        public void DisplayNoFramesRecentlyReceivedWarning()
        {
            txtWarning.Header = string.Format("Last frame received at {0}", webCamControl.cameraHandler.LastProcessedFrame.ToShortTimeString());
        }

        public void UpdateFPS()
        {
            //txtFPS.Header = webCamControl.CalcFPS().ToString("N2");
        }

        void WebCam3Window_Loaded(object sender, RoutedEventArgs e)
        {            
            selectCaptureDevice.CaptureDevices = new LocalVideoDevicesViewModel(null);
            btnSelectCapture.IsChecked = true;
        }

        public void SetPostProcessors(FilterCollection filters)
        {
            webCamControl.PostProcessors.Add(filters);
        }

        //void _motionProcessor_MotionDetected(object sender, ObjectEventArgs<FrameInfo> e)
        //{            
        //    if (_movementAlarmOn)
        //    {
        //        Dispatcher.BeginInvoke(new VoidDelegate(() =>
        //        {
        //            this.Topmost = true;
        //            btnTopmost.IsChecked = true;                    
        //            this.Activate();
        //            this.BringIntoView();
        //            this.Focus();

        //            System.Media.SystemSounds.Exclamation.Play();
        //            btnMovementAlarm.IsChecked = false;
        //        }));

        //        _movementAlarmOn = false;

        //    }
        //}

        void WebCam3Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            webCamControl.ShutdownCameraControl();
        }

        private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.Escape)
            {
                e.Handled = true;
                this.Close();
            }
        }

        private void btnTopmost_Checked(object sender, RoutedEventArgs e)
        {
            this.Topmost = true;
            this.Activate();
        }

        private void btnTopmost_Unchecked(object sender, RoutedEventArgs e)
        {
            this.Topmost = false;
            this.Activate();
        }

        public void StartupVideo()
        {
            if (_device == null || _device.DeviceName == "Remote Feed" || string.IsNullOrEmpty(_device.DeviceName))
            {
                if (!Communications.Connected)
                {
                    var success = Communications.TryConnect();
                }
            }
            else
            {
                webCamControl._videoDeviceToUse = _device;
                webCamControl.StartupWebCam();
                _handler = webCamControl.cameraHandler;
                _videoFeed = webCamControl.cameraHandler._videoFeed;
            }
        }

        private void btnStartStopVideo_Checked(object sender, RoutedEventArgs e)
        {
            StartupVideo();
        }

        private void btnStartStopVideo_Unchecked(object sender, RoutedEventArgs e)
        {
            webCamControl.ShutdownCameraControl();
        }

        private void txtMotion_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            txtMotion.Header = string.Empty;
        }

        private void btnClearFPS_Click(object sender, RoutedEventArgs e)
        {
            webCamControl.ResetFPS();
        }

        private void btnMotionSettings_Click(object sender, RoutedEventArgs e)
        {
            ShowProps1();
        }

        private void btnVideoSettings_Click(object sender, RoutedEventArgs e)
        {
            ShowProps2();
        }

        private void selectCaptureDevice_UseDevice(object sender, ObjectEventArgs<LocalVideoDevice> e)
        {
            _device = e.obj;
            selectCaptureDevice.Visibility = Visibility.Collapsed;
            if (Communications == null)
            {
                Communications = new Communications();

                if (_device == null || _device.DeviceName == "Remote Feed" || string.IsNullOrEmpty(_device.DeviceName))
                {
                    if (!_communicationsInitialized)
                    {
                        _communicationsInitialized = true;
                        Communications.Startup(false);
                    }
                }
            }
        }
    }
}
